FastAPI, Pydantic, REST API design — consolidate the week before going async in Week 13.
Day 60 of 80
By the end of this week you should be able to do all four of these. If any feel shaky, the review section below covers each one.
BaseModel, field_validator, and clear error responses/docs — test every endpoint interactivelyfrom fastapi import FastAPI, HTTPException
from pydantic import BaseModel, field_validator
from typing import Optional
app = FastAPI()
# 1. Path parameter — part of the URL, always required
@app.get("/prompts/{prompt_id}")
def get_prompt(prompt_id: int): # validated: must be int
...
# 2. Query parameter — after ?, optional with default
@app.get("/prompts")
def list_prompts(platform: Optional[str] = None):
... # /prompts?platform=Kling or just /prompts
# 3. Request body — JSON object sent by the client
class PromptIn(BaseModel):
platform: str
shot: str
prompt_text: str
@app.post("/prompts", status_code=201)
def create_prompt(prompt: PromptIn):
... # FastAPI parses and validates the JSON body
# 4. HTTPException — proper error responses
raise HTTPException(status_code=404, detail="Not found")
raise HTTPException(status_code=422, detail="Invalid input")
raise HTTPException(status_code=500, detail="Server error")
| Concern | Flask | FastAPI |
|---|---|---|
| Best for | Learning, HTML-rendering apps, simple APIs | Production APIs, data validation, async workloads |
| Route definition | @app.route("/", methods=["GET"]) |
@app.get("/") |
| Request validation | Manual — you write all checks | Automatic via Pydantic models |
| API documentation | Third-party (Flask-RESTx, flasgger) | Built in — auto-generated at /docs |
| Async support | Via flask[async] extension | Native — just use async def |
| Error responses | Return dicts manually | HTTPException with status codes |
| Dev server | Built-in Flask dev server | uvicorn (uvicorn api:app --reload) |
When a POST request arrives at a FastAPI route with a Pydantic model, here's exactly what happens — in order:
Content-Type: application/json header and parses the body@field_validator functions run in the order they're definedIn older Python web apps, developers wrote dozens of lines of if not data.get("platform") checks. Pydantic replaces all of that with a class definition. The validation logic lives in one place and is reusable across multiple routes.
Right now, if you call /generate for 3 platforms (Kling, Runway, Veo), here's what happens:
With async Python, all three requests fire at the same moment. You wait for the slowest one — about 2 seconds total. Same one worker. Three times faster.
This isn't parallel processing (multiple cores) — it's concurrent I/O. While one request is waiting for Claude to respond, Python does something else. It's the same pattern as a skilled restaurant server taking all the orders before going to the kitchen once.
async def, await, asyncio.gather(), asyncio.run(), anthropic.AsyncAnthropic() — you'll use all of these next week.
@field_validator/docsDay 61 starts with a Watch session covering the fundamentals of async/await. You'll see exactly why waiting for I/O is wasteful, and how Python's event loop lets you do many things at once with a single thread.